﻿using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Modules.CheckIn;
using Modules.CheckIn.Entitys;
using Modules.Device;
using Modules.Device.Entitys;
using Modules.Person;
using Modules.Project.Entitys;
using Modules.Project.EventArgs;
using Modules.Project.Repositories;
using PmSoft;
using PmSoft.ApplicationContext;
using PmSoft.Events;
using PmSoft.Exceptions;
using static Modules.Device.CheckInDeviceConstants;
using static Modules.Person.PersonConstants;

namespace Modules.Project
{
    [UseDI(ServiceLifetime.Scoped)]
    public class ProjectGroupMemberService
    {
        private readonly ProjectGroupMemberRepository projectGroupMenberRepository;
        private readonly ProjectInfoRepository projectInfoRepository;
        private readonly PersonService personService;
        private readonly IApplicationContext applicationContext;
        private readonly ILogger logger;
        private readonly IEventBus eventBus;

        public ProjectGroupMemberService(ProjectGroupMemberRepository projectGroupMenberRepository,
            IApplicationContext applicationContext,
            ProjectInfoRepository projectInfoRepository,
            PersonService personService,
             ILogger<ProjectGroupMemberService> logger,
             IEventBus eventBus
            )
        {
            this.projectGroupMenberRepository = projectGroupMenberRepository;
            this.applicationContext = applicationContext;
            this.personService = personService;
            this.logger = logger;
            this.projectInfoRepository = projectInfoRepository;
            this.eventBus = eventBus;
        }

        #region 增删改

        /// <summary>
        /// 创建成员
        /// </summary>
        /// <param name="entity"></param>
        public void Create(ProjectGroupMember entity)
        {
            projectGroupMenberRepository.Insert(entity);
        }

        public void Update(ProjectGroupMember entity)
        {
            if (projectGroupMenberRepository.ExistsByProjectPerson(entity, entity.Id))
                throw new BusinessException($"当前项目：人员{entity.PersonId} 已存在，不能编辑");
            projectGroupMenberRepository.Update(entity);
        }

        /// <summary>
        /// 删除多个组成员
        /// </summary>
        /// <param name="ids"></param>
        public void Delete(IEnumerable<int> ids)
        {
            foreach (int id in ids)
            {
                Delete(id);
            }
        }

        /// <summary>
        /// 删除成员
        /// </summary>
        /// <param name="id"></param>
        public void Delete(int id)
        {
            projectGroupMenberRepository.DeleteByEntityId(id);
        }

        /// <summary>
        /// 组是否存在组长
        /// </summary>
        /// <param name="groupId"></param>
        /// <param name="id"></param>
        /// <returns></returns>
        public bool HasLeader(int? groupId, int? id = null)
        {
            return projectGroupMenberRepository.HasLeader(groupId, id);
        }

        /// <summary>
        /// 批量更新组成员状态
        /// </summary>
        /// <param name="projectGroupMembers"></param>
        /// <param name="status"></param>
        public void Update(IEnumerable<ProjectGroupMember> projectGroupMembers, 进出场状态 status)
        {
            foreach (var item in projectGroupMembers)
            {
                item.Status = status;
                projectGroupMenberRepository.Update(item);
            }
            
        }


        /// <summary>
        /// 修改人员所在班组
        /// </summary>
        /// <param name="projectId"></param>
        /// <param name="personId"></param>
        /// <param name="oldGroupId"></param>
        /// <param name="newGroupId"></param>
        /// <param name="startDate"></param>
        /// <param name="endDate"></param>
        /// <exception cref="NotImplementedException"></exception>
        public void EditPersonGroupMember(int projectId, int personId, int oldGroupId, int newGroupId, DateTime startDate, DateTime endDate)
        {
            try
            {
                applicationContext.Transaction.Begin();//开始事务
                //先将原班组成员状态改为离场
                ProjectGroupMember? oldMember = GetProjectGroupMemberByGroupPerson(oldGroupId, personId);
                if (oldMember == null)
                    throw new BusinessException("班组信息不存在");
                oldMember.Status = 进出场状态.离场;
                oldMember.EndDate = startDate.AddDays(-1);
                projectGroupMenberRepository.Update(oldMember);

                //查询当前人更换的班组是否存在数据，若存在则删除
                ProjectGroupMember? newMember = GetProjectGroupMemberByGroupPerson(newGroupId, personId);
                if (newMember != null)
                {
                    newMember.StartDate = startDate;
                    newMember.EndDate = endDate;
                    newMember.Status = 进出场状态.进场;
                    newMember.IsLeader = false;
                    projectGroupMenberRepository.Update(newMember);
                }
                else
                {
                    //新增一条班组成员信息
                    newMember = new()
                    {
                        ProjectId = projectId,
                        GroupId = newGroupId,
                        CorpId = oldMember.CorpId,
                        PersonId = oldMember.PersonId,
                        Type = oldMember.Type,
                        IsLeader = false,
                        WorkDate = oldMember.WorkDate,
                        CreateTime = DateTime.Now,
                        IssueCardDate = oldMember.IssueCardDate,
                        IssueCardPic = oldMember.IssueCardPic,
                        StartDate = startDate,
                        EndDate = endDate,
                        Status = 进出场状态.进场
                    };
                    projectGroupMenberRepository.Insert(newMember);
                }

                applicationContext.Transaction.Complete();//完成事务
            }
            catch (Exception ex)
            {
                applicationContext.Transaction.Abort();//回滚事务
                logger.LogError(ex, $"更换班组失败:{oldGroupId}");
                throw new BusinessException("更换班组失败");
            }
        }

        /// <summary>
        /// 单个人员进场
        /// </summary>
        /// <param name="memberId"></param>
        /// <exception cref="BusinessException"></exception>
        public void InGroupMember(int memberId)
        {
            ProjectGroupMember? projectGroupMember = projectGroupMenberRepository.Get(memberId) ?? throw new BusinessException("当前成员不存在");
            //查询当前人员其他班组信息
            IEnumerable<ProjectGroupMember> projectGroupMembers = projectGroupMenberRepository.GetProjectGroupMembersByPersonId(projectGroupMember.PersonId);
            //将其他班组信息全部设置为离场
            projectGroupMembers = projectGroupMembers.Where(a => a.Id != projectGroupMember.Id);

            try
            {
                applicationContext.Transaction.Begin();//开始事务

                foreach (var item in projectGroupMembers)
                {
                    item.Status = 进出场状态.离场;
                    projectGroupMenberRepository.Update(item);
                }
                //将当前信息设置为进场
                projectGroupMember.Status = 进出场状态.进场;
                projectGroupMenberRepository.Update(projectGroupMember);
                applicationContext.Transaction.Complete();//完成事务

                var checkinDeviceCommandService = applicationContext.GetService<CheckinDeviceCommandService>();
                //写入命令
                checkinDeviceCommandService.Send(projectGroupMember.ProjectId, new CheckinDeviceCommand { Code = 考勤机命令.人员进场后下发, Name = 考勤机命令.人员进场后下发.GetDescription() });

            }
            catch (Exception ex)
            {
                applicationContext.Transaction.Abort();//回滚事务
                logger.LogError(ex, $"进场人员失败:{memberId}");
                throw new BusinessException("进场人员失败");
            }
        }

        /// <summary>
        /// 单个人员离场
        /// </summary>
        /// <param name="memberId"></param>
        /// <exception cref="BusinessException"></exception>
        public void OutGroupMember(int memberId, DateTime endDate)
        {
            ProjectGroupMember? projectGroupMember = projectGroupMenberRepository.Get(memberId);
            if (projectGroupMember == null)
                throw new BusinessException("当前成员不存在");
            //将当前信息设置为进场
            projectGroupMember.Status = 进出场状态.离场;
            projectGroupMember.EndDate = endDate;
            projectGroupMenberRepository.Update(projectGroupMember);

           var checkinDeviceCommandService= applicationContext.GetService<CheckinDeviceCommandService>();
           //写入命令
            checkinDeviceCommandService.Send(projectGroupMember.ProjectId,new CheckinDeviceCommand { Code= 考勤机命令.人员离场后下发,Name= 考勤机命令.人员离场后下发.GetDescription() });
          
        }

        /// <summary>
        /// 成员与项目解绑
        /// </summary>
        /// <param name="projectInfo"></param>
        /// <param name="member"></param>
        /// <exception cref="BusinessException"></exception>
        public void Unbind(ProjectInfo projectInfo, ProjectGroupMember member)
        {
            try
            {
                applicationContext.Transaction.Begin();//开始事务
                projectInfo.ManagerId = null;
                projectInfoRepository.Update(projectInfo);
                Delete(member.Id);
                applicationContext.Transaction.Complete();//完成事务
            }
            catch (Exception ex)
            {
                applicationContext.Transaction.Abort();//回滚事务
                logger.LogError(ex, $"解绑失败:{member.Id}");
                throw new BusinessException("解绑失败");
            }
        }

        /// <summary>
        /// 将当前人员转入管理组
        /// </summary>
        /// <param name="member"></param>
        /// <exception cref="NotImplementedException"></exception>
        public void TransferManager(ProjectGroupMember oldMember, ProjectGroupMember newMember)
        {
            try
            {
                applicationContext.Transaction.Begin();//开始事务
                oldMember.Status = 进出场状态.离场;
                oldMember.EndDate = newMember.StartDate;
                projectGroupMenberRepository.Update(oldMember);

                newMember.Status = 进出场状态.进场;
                projectGroupMenberRepository.Insert(newMember);

                applicationContext.Transaction.Complete();//完成事务
            }
            catch (Exception ex)
            {
                applicationContext.Transaction.Abort();//回滚事务
                logger.LogError(ex, $"转入管理组失败:{oldMember.Id}");
                throw new BusinessException("转入管理组失败");
            }
        }
        #endregion

        #region 查询
        /// <summary>
        /// 获取单个组成员
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public ProjectGroupMember? GetMember(int id)
        {
            return projectGroupMenberRepository.Get(id);
        }

        /// <summary>
        /// 根据人员id查询在场班组信息
        /// </summary>
        /// <param name="personId"></param>
        /// <returns></returns>
        public ProjectGroupMember? GetOnSiteMembers(int personId)
        {
            IEnumerable<ProjectGroupMember> projectGroupMembers = projectGroupMenberRepository.GetProjectGroupMembersByPersonId(personId);
            return projectGroupMembers.FirstOrDefault(a => a.Status == 进出场状态.进场);
        }

        public IPagedList<ProjectGroupMember> GetProjectGroupMembersByManager(ProjectGroupMemberQuery query, int pageIndex, int pageSize)
        {
            return projectGroupMenberRepository.GetProjectGroupMembersByManager(query, pageIndex, pageSize);
        }

        public IPagedList<ProjectGroupMember> GetProjectGroupMembers(ProjectGroupMemberQuery query, int pageIndex, int pageSize)
        {
            return projectGroupMenberRepository.GetProjectGroupMembers(query, pageIndex, pageSize);
        }

        public IEnumerable<ProjectGroupMember> GetProjectGroupMembersByGroupIds(IEnumerable<int> groupIds)
        {
            return projectGroupMenberRepository.GetProjectGroupMembersByGroupIds(groupIds);
        }

        public IEnumerable<ProjectGroupMember> GetProjectGroupMembersByCorpIds(IEnumerable<int> corpIds)
        {
            return projectGroupMenberRepository.GetProjectGroupMembersByCorpIds(corpIds);
        }

        public IEnumerable<ProjectGroupMember> GetProjectGroupMembersByPersonIds(IEnumerable<int> personIds)
        {
            return projectGroupMenberRepository.GetProjectGroupMembersByPersonIds(personIds);
        }

        public IEnumerable<ProjectGroupMember> GetProjectGroupMembersByOnlineGroupIds(IEnumerable<int> groupIds)
        {
            return projectGroupMenberRepository.GetProjectGroupMembersByGroupIds(groupIds).Where(a => a.Status == 进出场状态.进场);
        }

        public IEnumerable<ProjectGroupMember> GetProjectGroupMembersByCorpIdsAndProjectId(IEnumerable<int> corpIds, int projectId)
        {
            var data = GetProjectGroupMembersByProjectId(projectId);
            return data.Where(a => corpIds.Contains(a.CorpId));
        }

        /// <summary>
        /// 获取企业在指定项目下组成员
        /// </summary>
        /// <param name="corpId"></param>
        /// <param name="projectId"></param>
        /// <returns></returns>
        public IEnumerable<ProjectGroupMember> GetProjectGroupMembersByCorpIdAndProjectId(int corpId, int projectId)
        {
            return GetProjectGroupMembersByProjectId(projectId).Where(m => m.CorpId == corpId);
        }

        /// <summary>
        /// 获取项目下所有组成员
        /// </summary>
        /// <param name="projectId"></param>
        /// <returns></returns>
        public IEnumerable<ProjectGroupMember> GetProjectGroupMembersByProjectId(int projectId)
        {
            return projectGroupMenberRepository.GetProjectGroupMembersByProjectId(projectId);
        }

        /// <summary>
        /// 获取组下所有成员
        /// </summary>
        /// <param name="groupId"></param>
        /// <returns></returns>
        public IEnumerable<ProjectGroupMember> GetProjectGroupMembersByGroupId(int groupId)
        {
            return projectGroupMenberRepository.GetProjectGroupMembersByGroupId(groupId);
        }


        /// <summary>
        /// 根据成员ID集合获取组成员信息集合
        /// </summary>
        /// <param name="ids"></param>
        /// <returns></returns>
        public IEnumerable<ProjectGroupMember> GetProjectGroupMembers(IEnumerable<int> ids)
        {
            return projectGroupMenberRepository.PopulateEntitiesByEntityIds(ids);
        }

        /// <summary>
        /// 根据组ID和人员ID 查询参与组成员信息
        /// </summary>
        /// <param name="groupId"></param>
        /// <param name="personId"></param>
        /// <returns></returns>
        public ProjectGroupMember? GetProjectGroupMemberByGroupPerson(int groupId, int personId)
        {
            return GetProjectGroupMembersByGroupId(groupId).FirstOrDefault(m => m.PersonId == personId);
        }

        /// <summary>
        /// 人员的参与的组成员集合
        /// </summary>
        /// <param name="personId"></param>
        /// <returns></returns>
        public IEnumerable<ProjectGroupMember> GetProjectGroupMembersByPersonId(int personId)
        {
            return projectGroupMenberRepository.GetProjectGroupMembersByPersonId(personId);
        }

        /// <summary>
        /// 查询项目人员总数
        /// </summary>
        /// <param name="query"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        public int GetProjectPersonCount(ProjectCheckinCountQuery query)
        {
            return projectGroupMenberRepository.GetProjectPersonCount(query);
        }

        /// <summary>
        /// 查询班组人员数量
        /// </summary>
        /// <param name="query"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        public IEnumerable<PersonCount> GetPersonCountsByProjectId(ProjectCheckinCountQuery query)
        {
            return projectGroupMenberRepository.GetPersonCountsByProjectId(query);
        }

        /// <summary>
        /// 获取多个项目的组成员信息集合
        /// </summary>
        /// <param name="projectIds"></param>
        /// <returns></returns>
        public IEnumerable<ProjectGroupMember> GetProjectGroupMembersByProjectIds(IEnumerable<int> projectIds)
        {
            return projectGroupMenberRepository.GetProjectGroupMembersByProjectIds(projectIds);
        }
        #endregion
    }
}